home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / InstallInk < prev    next >
Text File  |  1992-08-11  |  19KB  |  931 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "Port.h"
  6.  
  7. #include "Class.h"
  8. #include "String.h"
  9. #include "Error.h"
  10. #include "Picture.h"
  11. #include "WindowSystem.h"
  12. #include "DevBitmap.h"
  13. #include "Math.h"
  14.  
  15. Port *Port::port, *Port::tbport;
  16. Ink *Port::tbink= 0;
  17. Point Port::tbpos, Port::tblastpos;
  18. Rectangle Port::tbbbox;
  19.  
  20. static inline void ScaleRect(Port *p, Rectangle &r)
  21. {
  22.     if (p->scale & 1) {
  23.     r.origin.x= (int) ((float)r.origin.x * p->scalex + 0.5);
  24.     r.origin.y= (int) ((float)r.origin.y * p->scaley + 0.5);
  25.     r.extent.x= (int) ((float)r.extent.x * p->scalex + 0.5);
  26.     r.extent.y= (int) ((float)r.extent.y * p->scaley + 0.5);
  27.     }
  28. }
  29.  
  30. static inline void ScalePoint(Port *port, Point &p)
  31. {
  32.     if (port->scale & 1) {
  33.     p.x= (int) ((float)p.x * port->scalex + 0.5);
  34.     p.y= (int) ((float)p.y * port->scaley + 0.5);
  35.     }
  36. }
  37.  
  38. static inline void ScaleInt(Port *p, int &i)
  39. {
  40.     if (p->scale & 1)
  41.     i= (int) ((float)i * p->scalex + 0.5);
  42. }
  43.  
  44. GrState::GrState(Port *p)
  45. {
  46.     if (p == 0)
  47.     port= Port::port;
  48.     else
  49.     port= p;
  50.     clip= port->cliprect;
  51.     origin= port->origin;
  52.     scalex= port->scalex;
  53.     scaley= port->scaley;
  54. }
  55.  
  56. GrState::~GrState()
  57. {
  58.     port->FlushMyText();
  59.     port->sfont= 0;
  60.     port->DevScale(scalex, scaley);
  61.     port->origin= origin;
  62.     port->Clip(clip);
  63. }
  64.  
  65. //---- Port --------------------------------------------------------------------
  66.  
  67. NewMetaImpl(Port,SysEvtHandler, (T(depth), T(hascolor)));
  68.  
  69. Port::Port() : SysEvtHandler(-1)
  70. {
  71.     PortInit();
  72.     hascolor= FALSE;
  73.     depth= gDepth;
  74. }
  75.  
  76. Port::~Port()
  77. {
  78.     if (port == this)
  79.     port= 0;
  80.     if (tbport == this)
  81.     tbport= 0;
  82. }
  83.  
  84. void Port::PortInit()
  85. {
  86.     scalex= scaley= 1.0;
  87.     scale= FALSE;
  88.     cliprect= Rectangle(0, 0, 30000, 30000);
  89.     origin= gPoint0;
  90.     SetNormal();
  91.     SetPenNormal();
  92.     SetTextNormal();
  93. }
  94.  
  95. //---- abstract cursor methods -------------------------------------------------
  96.  
  97. GrCursor Port::SetCursor(GrCursor c)
  98.     return c;
  99. }
  100.  
  101. GrCursor Port::SetWaitCursor(unsigned int, GrCursor c)
  102. {
  103.     if (this)
  104.     return SetCursor(c);
  105.     return c;
  106. }
  107.  
  108. GrCursor Port::GetCursor()
  109. {
  110.     return eCrsNone;
  111. }
  112.  
  113. //---- graphics context --------------------------------------------------------
  114.  
  115. void Port::SetPenNormal()
  116. {
  117.     pensize= 1;
  118.     penink= gInkBlack;
  119.     pencap= eDefaultCap;
  120. }
  121.  
  122. void Port::SetTextNormal()
  123. {
  124.     textink= gInkBlack;
  125.     textfont= gSysFont;
  126. }
  127.  
  128. //---- color halftoning (ordered dither) ---------------------------------------
  129.  
  130. extern Ink *Grey2Halftone(float f);
  131.  
  132. void Port::DevSetGrey(float f)
  133. {
  134.     InstallInk(Grey2Halftone(f));
  135. }
  136.  
  137. void Port::SetColor(RGBColor *cp)
  138. {
  139.     if (HasColor())
  140.     DevSetColor(cp);
  141.     else
  142.     DevSetGrey(cp->AsGreyLevel() / 255.0);
  143. }
  144.  
  145. //---- clipping ----------------------------------------------------------------
  146.  
  147. void Port::InitClip()
  148. {
  149.     FlushMyText();
  150.     sfont= 0;
  151.     DevScale(1.0, 1.0);
  152.     cliprect= Rectangle(0, 0, 30000, 30000);
  153.     DevClip(cliprect);
  154.     origin= gPoint0;
  155. }
  156.  
  157. void Port::Clip(Rectangle r)
  158. {
  159.     if (cliprect != r) {
  160.     FlushMyText();
  161.     cliprect= r;
  162.     DevClip(cliprect);
  163.     // scale|= 2;
  164.     }
  165. }
  166.  
  167. void Port::ClipFurther(Rectangle r)
  168. {
  169.     ScaleRect(this, r);
  170.     r.origin+= origin;
  171.     r.Clip(cliprect);
  172.     Clip(r);
  173. }
  174.  
  175. void Port::Scale(float x, float y)
  176. {
  177.     FlushMyText();
  178.     sfont= 0;
  179.     DevScale(x*scalex, y*scaley);
  180. }
  181.  
  182. void Port::Translate(Point o)
  183. {
  184.     ScalePoint(this, o);
  185.     origin+= o;
  186. }
  187.  
  188. bool Port::Visible(Ink *ink, Rectangle &r)
  189. {
  190.     if (ink != gInkNone && (WindowSystem::fullscreen || cliprect.Intersects(r))) {
  191.     if (scale & 2) {
  192.         DevClip(cliprect);
  193.         scale&= ~2;
  194.     }
  195.     FlushMyText();
  196.     InstallInk(ink);
  197.     return TRUE;
  198.     }
  199.     return FALSE;
  200. }
  201.  
  202. //---- graphic primitives ------------------------------------------------------
  203.  
  204. void Port::StrokeLine(Ink *ink, int psz, GrLineCap cap, Point p1, Point p2)
  205. {
  206.     if (ignore)
  207.     return;
  208.     if (scale & 1) {
  209.     ScalePoint(this, p1);
  210.     ScalePoint(this, p2);
  211.     ScaleInt(this, psz);
  212.     }
  213.     p1+= origin;
  214.     p2+= origin;
  215.     Rectangle rr= NormRect(p1,p2).Expand(Math::Max(2, psz)/2);
  216.     if (Visible(ink, rr))
  217.     DevStrokeLine(psz, &rr, cap, p1, p2);
  218. }
  219.  
  220. void Port::StrokeRect(Ink *ink, int psz, Rectangle r)
  221. {
  222.     if (ignore)
  223.     return;
  224.     if (scale & 1) {
  225.     ScaleRect(this, r);
  226.     ScaleInt(this, psz);
  227.     }
  228.     r.origin+= origin;
  229.     if (Visible(ink, r))
  230.     DevStrokeRect(psz, &r);
  231. }
  232.  
  233. void Port::FillRect(Ink *ink, Rectangle r)
  234. {
  235.     if (ignore)
  236.     return;
  237.     ScaleRect(this, r);
  238.     r.origin+= origin;
  239.     if (Visible(ink, r))
  240.     DevFillRect(&r);
  241. }
  242.  
  243. void Port::StrokeOval(Ink *ink, int psz, Rectangle r)
  244. {
  245.     if (ignore)
  246.     return;
  247.     if (scale & 1) {
  248.     ScaleRect(this, r);
  249.     ScaleInt(this, psz);
  250.     }
  251.     r.origin+= origin;
  252.     if (Visible(ink, r))
  253.     DevStrokeOval(psz, &r);
  254. }
  255.  
  256. void Port::FillOval(Ink *ink, Rectangle r)
  257. {
  258.     if (ignore)
  259.     return;
  260.     ScaleRect(this, r);
  261.     r.origin+= origin;
  262.     if (Visible(ink, r))
  263.     DevFillOval(&r);
  264. }
  265.  
  266. void Port::StrokeRRect(Ink *ink, int psz, Rectangle r, Point dia)
  267. {
  268.     if (ignore)
  269.     return;
  270.     if (scale & 1) {
  271.     ScaleRect(this, r);
  272.     ScalePoint(this, dia);
  273.     ScaleInt(this, psz);
  274.     }
  275.     r.origin+= origin;
  276.     if (Visible(ink, r))
  277.     DevStrokeRRect(psz, &r, dia);
  278. }
  279.  
  280. void Port::FillRRect(Ink *ink, Rectangle r, Point dia)
  281. {
  282.     if (ignore)
  283.     return;
  284.     if (scale & 1) {
  285.     ScaleRect(this, r);
  286.     ScalePoint(this, dia);
  287.     }
  288.     r.origin+= origin;
  289.     if (Visible(ink, r))
  290.     DevFillRRect(&r, dia);
  291. }
  292.  
  293. void Port::StrokeWedge(Ink *ink, int psz, GrLineCap cap, Rectangle r, int s, int l)
  294. {
  295.     if (ignore)
  296.     return;
  297.     if (l >= 360) {
  298.     StrokeOval(ink, psz, r);
  299.     return;
  300.     }
  301.     while (s < 0)
  302.     s+= 360;
  303.     while (s >= 360)
  304.     s-= 360;
  305.     if (scale & 1) {
  306.     ScaleRect(this, r);
  307.     ScaleInt(this, psz);
  308.     }
  309.     r.origin+= origin;
  310.     if (Visible(ink, r.WedgeBBox(s, l)))
  311.     DevStrokeWedge(psz, cap, &r, s, l);
  312. }
  313.  
  314. void Port::FillWedge(Ink *ink, Rectangle r, int s, int l)
  315. {
  316.     if (ignore)
  317.     return;
  318.     if (l >= 360) {
  319.     FillOval(ink, r);
  320.     return;
  321.     }
  322.     while (s < 0)
  323.     s+= 360;
  324.     while (s >= 360)
  325.     s-= 360;
  326.     ScaleRect(this, r);
  327.     r.origin+= origin;
  328.     if (Visible(ink, r.WedgeBBox(s, l)))
  329.     DevFillWedge(&r, s, l);
  330. }
  331.  
  332. void Port::StrokePolygon(Point at, Ink *ink, Point *pts,
  333.                 int npts, GrPolyType t, int psz, GrLineCap cap)
  334. {
  335.     if (ignore)
  336.     return;
  337.     if (pts && npts > 0) {
  338.     Point *p= (Point*) Alloca(npts * sizeof(Point));
  339.     Rectangle r(BoundingBox(npts, pts, p));
  340.     r.origin+= at;
  341.     if (scale & 1) {
  342.         ScaleRect(this, r);
  343.         ScaleInt(this, psz);
  344.         for (int i= 0; i < npts; i++)
  345.         ScalePoint(this, p[i]);
  346.     }
  347.     r.origin+= origin;
  348.     if (Visible(ink, r))
  349.         DevStrokePolygon(&r, p, npts, t, psz, cap);
  350.     Freea(p);
  351.     }
  352. }
  353.  
  354. void Port::FillPolygon(Point at, Ink *ink, Point *pts, int npts, GrPolyType t)
  355. {
  356.     if (ignore)
  357.     return;
  358.     if (pts && npts > 0) {
  359.     Point *p= (Point*) Alloca(npts * sizeof(Point));
  360.     Rectangle r= BoundingBox(npts, pts, p);
  361.     r.origin+= at;
  362.     if (scale & 1) {
  363.         ScaleRect(this, r);
  364.         for (int i= 0; i < npts; i++)
  365.         ScalePoint(this, p[i]);
  366.     }
  367.     r.origin+= origin;
  368.     if (Visible(ink, r))
  369.         DevFillPolygon(&r, p, npts, t);
  370.     Freea(p);
  371.     }
  372. }
  373.  
  374. void Port::ShowBitmap(Ink *ink, Rectangle r, Bitmap *bm)
  375. {
  376.     if (ignore)
  377.     return;
  378.     ScaleRect(this, r);
  379.     r.origin+= origin;
  380.     if (Visible(ink, r))
  381.     DevShowBitmap(&r, bm);
  382. }
  383.  
  384. void Port::ShowPicture(Rectangle r, Picture *pic)
  385. {
  386.     if (ignore || pic == 0)
  387.     return;
  388.     ScaleRect(this, r);
  389.     r.origin+= origin;
  390.     if (Visible(gInkBlack, r))
  391.     DevShowPicture(&r, pic);
  392. }
  393.  
  394. void Port::GiveHint(int code, int len, void *vp)
  395. {
  396.     Rectangle r;
  397.     
  398.     if (vp && len < 0)
  399.     len= strlen((const char*) vp) + 1;
  400.     
  401.     switch (code) {
  402.  
  403.     case eHintBatch:
  404.     r= *((Rectangle*) vp);
  405.     ScaleRect(this, r);
  406.     r.origin+= origin;
  407.     DevGiveHint(code, len, &r);
  408.     break;
  409.     
  410.     default:
  411.     DevGiveHint(code, len, vp);
  412.     break;
  413.     }
  414. }
  415.  
  416. //---- Text ---------------------------------------------------------------------
  417.  
  418. void Port::SetFamily(GrFont fid)
  419. {
  420.     textfont= new_Font(fid, textfont->Size(), textfont->Face());
  421.     sfont= 0;
  422. }
  423.  
  424. void Port::SetSize(int ps)
  425. {
  426.     textfont= new_Font(textfont->Fid(), ps, textfont->Face());
  427.     sfont= 0;
  428. }
  429.  
  430. void Port::SetFace(GrFace face)
  431. {
  432.     textfont= new_Font(textfont->Fid(), textfont->Size(), face);
  433.     sfont= 0;
  434. }
  435.  
  436. void Port::SetFont(Font *fd)
  437. {
  438.     if (textfont != fd) {
  439.     textfont= fd;
  440.     sfont= 0;
  441.     }
  442. }
  443. //---- text batch --------------------------------------------------------------
  444.  
  445. void Port::flushtext()
  446. {
  447.     if (scale & 2) {
  448.     DevClip(cliprect);
  449.     scale&= ~2;
  450.     }
  451.     InstallInk(tbink);
  452.     DevShowTextBatch(&tbbbox, tbpos+origin);
  453.     tbport= 0;
  454. }
  455.  
  456. int Port::ShowChar(Font *fdp, Ink *ink, Point pos, byte c)
  457. {
  458.     byte s[2];
  459.     s[0]= c;
  460.     s[1]= 0;
  461.     return ShowString(fdp, ink, pos, s, 1);
  462. }
  463.  
  464. Ink *gTbInk;
  465.  
  466. int Port::ShowString(Font *fdp, Ink *ink, Point pos, byte *s, int l)
  467. {
  468.     Rectangle rr;
  469.     register int w, sl= 0;
  470.     byte c, *ss= s;
  471.     int ll= l;
  472.  
  473.     if (ignore || s == 0)
  474.     return 0;
  475.  
  476.     if (fdp != lastfdp) {
  477.     lastfdp= fdp;
  478.     sfont= 0;
  479.     }
  480.     
  481.     if (scale & 1) {
  482.     if (sfont == 0) {
  483.         int ss= fdp->Size();
  484.         ScaleInt(this, ss);
  485.         sfont= new_Font(fdp->Fid(), ss, fdp->Face());
  486.     }
  487.     fdp= sfont;
  488.     ScalePoint(this, pos);
  489.     }
  490.     
  491.     rr.origin= pos;
  492.     rr.origin+= origin;
  493.     rr.origin.y-= fdp->Ascender();
  494.     rr.extent.y= fdp->Spacing();
  495.  
  496.     while (l-- && (c= *s++)) {
  497.     rr.extent.x= w= fdp->Width(c);
  498.     if (WindowSystem::fullscreen || cliprect.Intersects(rr)) {
  499.         if (scale & 2) {
  500.         DevClip(cliprect);
  501.         scale&= ~2;
  502.         }
  503.         if (this != tbport || ink != tbink)
  504.         FlushAnyText();
  505.         gTbInk= ink;
  506.         DevShowChar(fdp, pos-tblastpos, c, &rr);
  507.         if (tbport == 0) {
  508.         tbport= this;
  509.         tbink= ink;
  510.         tbpos= pos;
  511.         tbbbox= rr;
  512.         } else
  513.         tbbbox.Merge(rr);
  514.         tblastpos.x= pos.x + w;
  515.         tblastpos.y= pos.y;
  516.     }
  517.     rr.origin.x+= w;
  518.     pos.x+= w;
  519.     sl+= w;
  520.     }
  521.     if (scale & 1)
  522.     return lastfdp->Width(ss, ll);
  523.     return sl;
  524. }
  525.  
  526. //---- device dependent methods ------------------------------------------------
  527.  
  528. void Port::DevClip(Rectangle)
  529. {
  530.     AbstractMethod("DevClip");
  531. }
  532.  
  533. void Port::DevFillRect(Rectangle*)
  534. {
  535.     AbstractMethod("DevFillRect");
  536. }
  537.  
  538. void Port::DevShowBitmap(Rectangle*, struct Bitmap*)
  539. {
  540.     AbstractMethod("DevShowBitmap");
  541. }
  542.  
  543. void Port::DevShowChar(Font*, Point, byte, Rectangle*)
  544. {
  545. }
  546.  
  547. void Port::DevShowTextBatch(Rectangle*, Point)
  548. {
  549.     AbstractMethod("DevShowTextBatch");
  550. }
  551.  
  552. void Port::DevGiveHint(int, int, void*)
  553. {
  554. }
  555.  
  556. void Port::DevSetPattern(struct DevBitmap*)
  557. {
  558. }
  559.  
  560. bool Port::DevSetColor(RGBColor *cp)
  561. {
  562.     cp->SetId(-1);
  563.     return TRUE;
  564. }
  565.  
  566. void Port::DevSetOther(int)
  567. {
  568. }
  569.  
  570. bool Port::DevImageCacheBegin(ImageCache*, Rectangle)
  571. {
  572.     return TRUE;    // need redraw
  573. }
  574.  
  575. void Port::DevImageCacheEnd(ImageCache*)
  576. {
  577. }
  578.  
  579. bool Port::DevScale(float ssx, float ssy)
  580. {
  581.     scalex= ssx;
  582.     scaley= ssy;
  583.     if (scalex != 1.0 || scaley != 1.0)
  584.     scale|= 1;
  585.     else
  586.     scale&= ~1;
  587.     return FALSE;   // FALSE means: can't scale
  588. }
  589.  
  590. void Port::DevShowPicture(Rectangle *r, Picture *pic)
  591. {
  592.     pic->Show(r, this);
  593. }
  594.  
  595. //---- window system independent graphic methods -------------------------------
  596.  
  597. Point Port::DevDrawArrow(int psz, Point s, Point e)
  598. {
  599.     int arrowwidth= Math::Max(6, psz*4+2), arrowlen= Math::Max(9, psz*7);
  600.     Point c, pts[3], ee(arrowwidth/2, arrowlen);
  601.     
  602.     if (Length(e-s) < arrowlen)
  603.     return e;     // too short, give up
  604.  
  605.     double ph= Phi(e-s), rot= Phi(ee), hyp= Length(ee);
  606.  
  607.     pts[0]= e;
  608. #ifdef PETERFIX
  609. // special case: going straight down
  610.     pts[1]= e + Point(-(arrowwidth/2),-arrowlen);
  611.     pts[2]= e + Point(arrowwidth/2,-arrowlen);
  612. #else
  613.     pts[1]= e + PolarToPoint(ph+rot, hyp, hyp);
  614.     pts[2]= e + PolarToPoint(ph-rot, hyp, hyp);
  615. #endif
  616.     c= Half(pts[1]+pts[2]);
  617.     
  618.     Rectangle rr= BoundingBox(3, pts);
  619.     DevFillPolygon2(&rr, pts, 3, ePolyDefault);
  620.     
  621.     return c;
  622. }
  623.  
  624. void Port::DevStrokeLine(int psz, Rectangle *r,
  625.                     GrLineCap cap, Point start, Point end)
  626. {
  627.     if (cap & eStartArrow)
  628.     start= DevDrawArrow(psz, end, start);
  629.     if (cap & eEndArrow)
  630.     end= DevDrawArrow(psz, start, end);
  631.     DevStrokeLine2(psz, r, cap, start, end);
  632. }
  633.  
  634. void Port::DevStrokeRect(int psz, Rectangle *r)
  635. {
  636.     int rpsz= (psz <= 0) ? 1 : psz;
  637.     
  638.     rpsz*= 2;
  639.     if (rpsz >= r->extent.x || rpsz >= r->extent.y)
  640.     DevFillRect(r);
  641.     else
  642.     DevStrokeRect2(psz, r);
  643. }
  644.  
  645. //---- splines -----------------------------------------------------------------
  646.  
  647. /*
  648.  * bez: Subdivide a Bezier spline, until it is thin enough to be
  649.  *      considered a line. Store line point in static array points.
  650. */
  651.  
  652. #define FIX(a) (((int) (a)) << 16)
  653. #define INT(a) (((a) + (1 << 15)) >> 16 )
  654. #define DELTA 1
  655.  
  656. static void bez(Point **gPp, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3)
  657. {
  658.     int maxx= Math::Max(x0, x3), minx= Math::Min(x0, x3), maxy= Math::Max(y0, y3), miny= Math::Min(y0, y3);
  659.     register int tx, ty;
  660.     
  661.     if (x1 >= minx && x1 <= maxx && y1 >= miny && y1 <= maxy
  662.         && x2 >= minx && x2 <= maxx && y2 >= miny && y2 <= maxy) {
  663.     register int ax, ay, dx= INT(x3-x0), dy= INT(y3-y0);
  664.     if (dx == 0 || dy == 0) {
  665.         (*gPp)->x= INT(x3);
  666.         (*gPp)++->y= INT(y3);
  667.         return;
  668.     }
  669.     ax= ((dy*INT(x1-x0))/dx)+INT(y0-y1);
  670.     ay= ((dx*INT(y1-y0))/dy)+INT(x0-x1);
  671.     if (Math::Abs(ax*ay) <= DELTA) {
  672.         (*gPp)->x= INT(x3);
  673.         (*gPp)++->y= INT(y3);
  674.         return;
  675.     }
  676.     ax= ((dy*INT(x2-x0))/dx)+INT(y0-y2);
  677.     ay= ((dx*INT(y2-y0))/dy)+INT(x0-x2);
  678.     if (Math::Abs(ax*ay) <= DELTA) {
  679.         (*gPp)->x= INT(x3);
  680.         (*gPp)++->y= INT(y3);
  681.         return;
  682.     }
  683.     }
  684.     
  685.     tx= (x0 >> 3) + 3 * (x1 >> 3) + 3 * (x2 >> 3) + (x3 >> 3);
  686.     ty= (y0 >> 3) + 3 * (y1 >> 3) + 3 * (y2 >> 3) + (y3 >> 3);
  687.     bez(gPp, x0, y0, (x0 >> 1) + (x1 >> 1), (y0 >> 1) + (y1 >> 1),
  688.         (x0 >> 2) + (x1 >> 1) + (x2 >> 2),
  689.         (y0 >> 2) + (y1 >> 1) + (y2 >> 2),
  690.         tx, ty);
  691.     bez(gPp, tx, ty, (x3 >> 2) + (x2 >> 1) + (x1 >> 2),
  692.         (y3 >> 2) + (y2 >> 1) + (y1 >> 2),
  693.         (x3 >> 1) + (x2 >> 1), (y3 >> 1) + (y2 >> 1),
  694.         x3, y3);
  695. }
  696.  
  697. static int makespline(Point *pts, Point *p, int n, GrPolyType)
  698. {
  699.     register int i;
  700.     Point *gPp= pts;
  701.     
  702.     gPp->x= p[0].x;
  703.     (gPp++)->y= p[0].y;
  704.     for (i= 0; i < n-1; i+= 3)
  705.     bez(&gPp, FIX(p[i+0].x), FIX(p[i+0].y), FIX(p[i+1].x), FIX(p[i+1].y),
  706.          FIX(p[i+2].x), FIX(p[i+2].y), FIX(p[i+3].x), FIX(p[i+3].y));
  707.     
  708.     return gPp - pts;
  709. }
  710.  
  711. void Port::DevStrokePolygon(Rectangle *r,
  712.         Point *pts, int npts, GrPolyType t, int psz, GrLineCap cap)
  713. {
  714.     Point *tmppts= 0;
  715.     
  716.     if (cap & eStartArrow)
  717.     DevDrawArrow(psz, pts[1]+r->origin, pts[0]+r->origin);
  718.     if (cap & eEndArrow)
  719.     DevDrawArrow(psz, pts[npts-2]+r->origin, pts[npts-1]+r->origin);
  720.     if (t & ePolyBezier) {
  721.     tmppts= (Point*) Alloca(sizeof(Point) * npts * 30);
  722.     int nn= makespline(tmppts, pts, npts, t);
  723.     if (nn > 0) {
  724.         pts= tmppts;
  725.         npts= nn;
  726.     }
  727.     }
  728.     DevStrokePolygon2(r, pts, npts, ePolyDefault, psz, cap);
  729.     Freea(tmppts);
  730. }
  731.  
  732. void Port::DevFillPolygon(Rectangle *r, Point *pts, int npts, GrPolyType t)
  733. {
  734.     Point *tmppts= 0;
  735.     if (t & ePolyBezier) {
  736.     tmppts= (Point*) Alloca(sizeof(Point) * npts * 30);
  737.     int nn= makespline(tmppts, pts, npts, t);
  738.     if (nn > 0) {
  739.         pts= tmppts;
  740.         npts= nn;
  741.     }
  742.     }
  743.     DevFillPolygon2(r, pts, npts, ePolyDefault);
  744.     Freea(tmppts);
  745. }
  746.  
  747. void Port::DevStrokeWedge(int psz, GrLineCap cap, Rectangle *r, int s, int d)
  748. {
  749.     int rpsz= (psz <= 0) ? 1 : psz;
  750.     rpsz*= 2;
  751.     if (rpsz >= r->extent.x || rpsz >= r->extent.y) {
  752.     DevFillWedge(r, s, d);
  753.     return;
  754.     }
  755.     if (r->extent.x < 4 || r->extent.y < 4) {
  756.     DevStrokeRect(psz, r);
  757.     return;
  758.     }
  759.     if (cap & eStartArrow) {
  760.     DevDrawArrow(psz, r->OvalAngleToPoint(s+10), r->OvalAngleToPoint(s));
  761.     // s+= 10; d-= 10;
  762.     }
  763.     if (cap & eEndArrow) {
  764.     DevDrawArrow(psz, r->OvalAngleToPoint(s+d-10), r->OvalAngleToPoint(s+d));
  765.     // d-= 10;
  766.     }
  767.     DevStrokeWedge2(psz, cap, r, s, d);
  768. }
  769.  
  770. void Port::DevFillWedge(Rectangle *r, int s, int d)
  771. {
  772.     if (r->extent.x < 4 || r->extent.y < 4)
  773.     DevFillRect(r);
  774.     else
  775.     DevFillWedge2(r, s, d);
  776. }
  777.  
  778. static void Wedge2Polygon(Point *pts, int &n, Point e2, float start, float len)
  779. {
  780.     if (len < 10)    // consider it a line
  781.     pts[n++]= PolarToPoint(start, e2.x, e2.y) + e2;
  782.     else {                  // subdivide
  783.     Wedge2Polygon(pts, n, e2, start, len/2);
  784.     Wedge2Polygon(pts, n, e2, start+len/2, len/2);
  785.     }
  786. }
  787.  
  788. void Port::DevStrokeWedge2(int psz, GrLineCap cap, Rectangle *r, int start, int len)
  789. {
  790.     Point *pts= (Point*) Alloca(sizeof(Point) * len);
  791.     Point e2= (r->extent-psz)/2;
  792.     int n= 0;
  793.  
  794.     Wedge2Polygon(pts, n, e2, start, len);
  795.     pts[n++]= PolarToPoint(start+len, e2.x, e2.y) + e2;
  796.     r->origin+= psz/2;
  797.     DevStrokePolygon2(r, pts, n, ePolyDefault, psz, cap);
  798.     Freea(pts);
  799. }
  800.  
  801. void Port::DevFillWedge2(Rectangle *r, int start, int len)
  802. {
  803.     Point *pts= (Point*) Alloca(sizeof(Point) * len);
  804.     Point e2= r->extent/2;
  805.     int n= 0;
  806.  
  807.     pts[n++]= e2;
  808.     Wedge2Polygon(pts, n, e2, start, len);
  809.     pts[n++]= PolarToPoint(start+len, e2.x, e2.y) + e2;
  810.     DevFillPolygon2(r, pts, n, ePolyDefault);
  811.     Freea(pts);
  812. }
  813.  
  814. void Port::DevStrokeRRect(int psz, Rectangle *r, Point dia)
  815. {
  816.     int rpsz= (psz <= 0) ? 1 : psz;
  817.     
  818.     rpsz*= 2;
  819.     if (rpsz >= r->extent.x || rpsz >= r->extent.y) {
  820.     DevFillRRect(r, dia);
  821.     return;
  822.     }
  823.     if (Math::Odd(dia.x))    // force to be even
  824.     dia.x--;
  825.     if (Math::Odd(dia.y))    // force to be even
  826.     dia.y--;
  827.     
  828.     if (dia.x >= r->extent.x && dia.y >= r->extent.y)
  829.     DevStrokeOval(psz, r);
  830.     else
  831.     DevStrokeRRect2(psz, r, Min(dia, r->extent));
  832. }
  833.  
  834. void Port::DevFillRRect(Rectangle *r, Point dia)
  835. {
  836.     if (Math::Odd(dia.x))    // force to be even
  837.     dia.x--;
  838.     if (Math::Odd(dia.y))    // force to be even
  839.     dia.y--;
  840.     
  841.     if (dia.x > r->extent.x && dia.y > r->extent.y)
  842.     DevFillOval(r);
  843.     else
  844.     DevFillRRect2(r, Min(dia, r->extent));
  845. }
  846.  
  847. void Port::DevStrokeOval(int psz, Rectangle *r)
  848. {
  849.     int rpsz= (psz <= 0) ? 1 : psz;
  850.     
  851.     rpsz*= 2;
  852.     if (rpsz >= r->extent.x || rpsz >= r->extent.y)
  853.     DevFillOval(r);
  854.     else if (r->extent.x < 4 || r->extent.y < 4)
  855.     DevStrokeRect(psz, r);
  856.     else
  857.     DevStrokeOval2(psz, r);
  858. }
  859.  
  860. void Port::DevFillOval(Rectangle *r)
  861. {
  862.     if (r->extent.x < 4 || r->extent.y < 4)
  863.     DevFillRect(r);
  864.     else
  865.     DevFillOval2(r);
  866. }
  867.  
  868. void Port::DevStrokeOval2(int psz, Rectangle *r)
  869. {
  870.     DevStrokeRRect2(psz, r, r->extent);
  871. }
  872.  
  873. void Port::DevFillOval2(Rectangle *r)
  874. {
  875.     DevFillRRect2(r, r->extent);
  876. }
  877.  
  878. //---- abstract methods --------------------------------------------------------
  879.  
  880. void Port::DevStrokeRect2(int, Rectangle*)
  881. {
  882.     AbstractMethod("DevStrokeRect2");
  883. }
  884.  
  885. void Port::DevStrokeRRect2(int, Rectangle*, Point)
  886. {
  887.     AbstractMethod("DevStrokeRRect2");
  888. }
  889.  
  890. void Port::DevFillRRect2(Rectangle*, Point)
  891. {
  892.     AbstractMethod("DevFillRRect2");
  893. }
  894.  
  895. void Port::DevStrokePolygon2(Rectangle*, Point*, int, GrPolyType, int, GrLineCap)
  896. {
  897.     AbstractMethod("DevStrokePolygon2");
  898. }
  899.  
  900. void Port::DevFillPolygon2(Rectangle*, Point*, int, GrPolyType)
  901. {
  902.     AbstractMethod("DevFillPolygon2");
  903. }
  904.  
  905. void Port::DevStrokeLine2(int, Rectangle*, GrLineCap, Point, Point)
  906. {
  907.     AbstractMethod("DevStrokeLine2");
  908. }
  909.  
  910. //---- Utilities ---------------------------------------------------------------
  911.  
  912. void DrawShadow(Rectangle &r, Point delta, Ink* fg, Ink *bg)
  913. {
  914.     if (delta != gPoint0) {
  915.     Rectangle sr(r);
  916.     sr.origin.x+= sr.extent.x;
  917.     sr.origin.y+= delta.y;
  918.     sr.extent.x= delta.x;
  919.     GrPaintRect(sr, bg);
  920.     sr= r;
  921.     sr.origin.x+= delta.x;
  922.     sr.origin.y+= sr.extent.y;
  923.     sr.extent.y= delta.y;
  924.     GrPaintRect(sr, bg);
  925.     }
  926.     GrPaintRect(r, fg);
  927.     GrStrokeRect(r);
  928. }
  929.    
  930.